package judesart.app.client.project.ui;

import gwtupload.client.IUploader;
import gwtupload.client.MultiUploader;
import gwtupload.client.IFileInput.AnchorFileInput;
import gwtupload.client.IUploader.OnFinishUploaderHandler;
import gwtupload.client.IUploader.OnStartUploaderHandler;

import java.util.ArrayList;
import java.util.List;

import judesart.app.client.project.ProjectController;
import judesart.app.client.project.ProjectControllerAsync;
import judesart.app.client.widget.TopInfo;
import judesart.app.domain.Project;
import judesart.app.domain.ProjectPhoto;

import com.allen_sauer.gwt.log.client.Log;
import com.extjs.gxt.ui.client.Style.Scroll;
import com.extjs.gxt.ui.client.data.BaseListLoadConfig;
import com.extjs.gxt.ui.client.data.BaseListLoader;
import com.extjs.gxt.ui.client.data.BeanModel;
import com.extjs.gxt.ui.client.data.BeanModelReader;
import com.extjs.gxt.ui.client.data.ListLoadResult;
import com.extjs.gxt.ui.client.data.ListLoader;
import com.extjs.gxt.ui.client.data.MemoryProxy;
import com.extjs.gxt.ui.client.event.ButtonEvent;
import com.extjs.gxt.ui.client.event.Events;
import com.extjs.gxt.ui.client.event.Listener;
import com.extjs.gxt.ui.client.event.SelectionChangedEvent;
import com.extjs.gxt.ui.client.store.ListStore;
import com.extjs.gxt.ui.client.widget.Composite;
import com.extjs.gxt.ui.client.widget.LayoutContainer;
import com.extjs.gxt.ui.client.widget.ListView;
import com.google.gwt.core.client.GWT;
import com.google.gwt.http.client.Request;
import com.google.gwt.http.client.RequestBuilder;
import com.google.gwt.http.client.RequestCallback;
import com.google.gwt.http.client.RequestException;
import com.google.gwt.http.client.Response;
import com.google.gwt.user.client.rpc.AsyncCallback;

public class PhotosPanel extends Composite {
    ProjectControllerAsync service = GWT.create(ProjectController.class);
    private final LayoutContainer photosLayoutContainer;
    private Project project;
    private final List<ProjectPhoto> photos = new ArrayList<ProjectPhoto>();

    private final ListLoader<ListLoadResult<ProjectPhoto>> loader;

    public PhotosPanel(Project project) {
        setProject(project);
        photosLayoutContainer = new LayoutContainer();
        photosLayoutContainer.setSize(798, 450);
        photosLayoutContainer.setBorders(false);
        photosLayoutContainer.setScrollMode(Scroll.AUTO);

        MemoryProxy<List<ProjectPhoto>> proxy = new MemoryProxy<List<ProjectPhoto>>(photos);

        loader = new BaseListLoader<ListLoadResult<ProjectPhoto>>(proxy, new BeanModelReader());
        ListStore<BeanModel> store = new ListStore<BeanModel>(loader);
        loader.load();

        final ListView<BeanModel> photosListView = new ListView<BeanModel>(store);
        photosListView.setLoadingText("loading...");
        photosListView.setBorders(false);
        photosListView.setTemplate(getTemplate());
        photosListView.setItemSelector("div.thumb-wrap");
        photosListView.getSelectionModel().addListener(Events.SelectionChange,
                new Listener<SelectionChangedEvent<BeanModel>>() {
                    public void handleEvent(SelectionChangedEvent<BeanModel> be) {
                        onSelectionChanged(be);
                    }
                });

        photosLayoutContainer.add(photosListView);

        MultiUploader defaultUploader = new MultiUploader();

        defaultUploader.addOnFinishUploadHandler(new OnFinishUploaderHandler() {

            @Override
            public void onFinish(IUploader uploader) {
                TopInfo.display("Info", "Upload : "
                        + uploader.getStatus().name());
                RequestBuilder builder = new RequestBuilder(RequestBuilder.GET, "/commitimages?action=addToProjectPhoto&projectId="
                        + getProject().getId());
                try {
                    builder.sendRequest(null, new RequestCallback() {

                        @Override
                        public void onResponseReceived(Request request,
                                Response response) {
                            Log.debug("onFinish -> " + response.getText());
                            addPhotoToPanel(response.getText());
                        }

                        @Override
                        public void onError(Request request, Throwable exception) {
                            Log.error("Error sending commit request", exception);
                            TopInfo.display("Error", "Unable to add images");
                        }
                    });
                } catch (RequestException e) {
                    Log.error("Error sending commit request", e);
                    TopInfo.display("Error", "Unable to add images");
                }
            }
        });
        defaultUploader.setMaximumFiles(10);
        defaultUploader.setFileInputPrefix("default");
        defaultUploader.avoidRepeatFiles(true);
        defaultUploader.setFileInput(new AnchorFileInput());
        defaultUploader.addOnStartUploadHandler(new OnStartUploaderHandler() {
            @Override
            public void onStart(IUploader uploader) {
                uploader.setServletPath("/upload");
            }
        });

        photosLayoutContainer.add(defaultUploader);

        initComponent(photosLayoutContainer);
    }

    private void addPhotoToPanel(String imageId) {
        Log.debug("addPhotoToPanel -> imageId [" + imageId + "]");
        final ProjectPhoto data = new ProjectPhoto();
        data.setImageId(new Long(imageId));
        service.findPhotoKeyByImageId(data.getImageId(),
                new AsyncCallback<String>() {
                    @Override
                    public void onFailure(Throwable caught) {
                        Log.error("Unable to get photo key fo image.", caught);
                    }

                    @Override
                    public void onSuccess(String result) {
                        Log.debug(" got key for image [" + result + "]");
                        data.setKey(result);
                    }
                });
        data.setImageId(new Long(imageId));
        data.setDescription("");
        photos.add(data);
        loader.load();
        photosLayoutContainer.layout();
    }

    protected Project getProject() {
        return project;
    }

    protected void setProject(Project project) {
        this.project = project;
        photos.clear();
        if (project != null && project.getPhotos() != null
                && project.getPhotos().size() > 0) {
            photos.addAll(project.getPhotos());
        }
    }

    protected void openProject(Project project) {
        setProject(project);
        loader.load(new BaseListLoadConfig());
        photosLayoutContainer.layout();
    }

    private native String getTemplate() /*-{
        return ['<tpl for=".">', 
        '<div style="border: 1px solid #FFFFFF;float:left;margin:4px 0 4px  4px; padding:2px;width:244px; height: 300px;" class="thumb-wrap" id="{imageId}">', 
        '<div style="width: 240px;" class="thumb"><img src="/image?id={imageId}&size=240x240"></div>', 
        '<div style="width: 100%; text-align: center; color: #999999;">{description}</div>',
        '</div>',
        '</tpl>', 
        '<div class="x-clear"></div>'].join("");
    }-*/;

    private void onSelectionChanged(SelectionChangedEvent<BeanModel> be) {
        Object source = be.getSource();
        Log.debug("source [" + source + "]");
        if (be.getSelection().size() == 0) {
            return;
        }
        final BeanModel model = be.getSelection().get(0);
        final ImageDialog imageDialog = new ImageDialog();
        imageDialog.setImageUrl("/image?id=" + model.get("imageId")
                + "&size=600x500");
        imageDialog.setTextAreaValue((String) model.get("description"));
        imageDialog.addSaveListener(new Listener<ButtonEvent>() {
            public void handleEvent(ButtonEvent be) {
                updatePhotoDescription(model, imageDialog.getTextAreaValue());
                imageDialog.hide();
            };
        });
        imageDialog.addDeleteListener(new Listener<ButtonEvent>() {
            @Override
            public void handleEvent(ButtonEvent be) {
                deletePhotoFromProject(model);
                imageDialog.hide();
            }
        });
        imageDialog.show();
    }

    private void deletePhotoFromProject(final BeanModel model) {
        final Long imageId = model.get("imageId");
        service.deletePhotoFromProject(project.getId(), imageId,
                new AsyncCallback<Void>() {
                    @Override
                    public void onFailure(Throwable caught) {
                        TopInfo.display("Error", "Unable to delete photo");
                    }

                    @Override
                    public void onSuccess(Void result) {
                        TopInfo.display("Info", "Photo deleted sucessfully");
                        for (ProjectPhoto photo : photos) {
                            if (photo.getImageId() == imageId) {
                                photos.remove(photo);
                                break;
                            }
                        }
                        loader.load();
                    }
                });
    }

    private void updatePhotoDescription(final BeanModel model,
            String description) {
        service.updatePhotoDescription((String) model.get("key"), description,
                new AsyncCallback<String>() {
                    @Override
                    public void onFailure(Throwable caught) {
                        TopInfo.display("Error", "Unable to update description");
                    }

                    @Override
                    public void onSuccess(String result) {
                        TopInfo.display("Info", "Description updated");
                        model.set("description", result);
                        loader.load();
                    }
                });
    }
}
